package scenetracer.core.primitive;

import java.util.LinkedList;
import java.util.List;

import scenetracer.core.Primitive;
import scenetracer.core.Ray;
import scenetracer.core.primitive.IntersectionState.IntersectionKind;
import scenetracer.math.Matrix4;
import scenetracer.math.Point2;
import scenetracer.math.Point3;
import scenetracer.math.Vector3;

public class TriangleMesh extends Primitive{
	private LinkedList<Triangle> triangles;
	private Triangle triOwner;
	public Point3 min, max;

	public TriangleMesh() {
		this.triangles = new LinkedList<Triangle>();

	}

	
	public TriangleMesh(LinkedList<Triangle> triangleList,
			Matrix4 transformation, Point3 min,
			Point3 max) {
		
		this.triangles = triangleList;

		transform(transformation);

		this.min = min;
		this.max = max;
		
		findMinMaxTransformed();
		
	}
	


	protected void transform(Matrix4 transform) {
		if (transform == null) {
			//throw new IllegalArgumentException();
			return;
		}

		for (Triangle triangle : triangles) {
			triangle.transform(transform);
		}
	}

	
	public void add(Triangle t) {
		this.triangles.add(t);
	}

	public IntersectionState Intersect(Point3 origin, Vector3 orientation) {
		
		if (origin == null || orientation == null) {
			throw new IllegalArgumentException();
		}

		Point3 result = null;
		Vector3 normalAux = null;
		float distance, minDistance = Integer.MAX_VALUE;
		Triangle triangleOwner = null;

		for (Triangle triangle : triangles) {

			Point3 pointAux = triangle.findIntersectionWithLine(origin,
					orientation);
			if (pointAux != null) {
				
				if ((distance = origin.distanceTo(pointAux)) < minDistance) {
					minDistance = distance;
					result = pointAux;
					//tmpNormalVector = triangle.normalVector;
					normalAux = triangle.getNormal(result);
					triangleOwner = triangle;
				}
			}
		}

		if (result == null) {
			return null;
		}
		
		triOwner = triangleOwner;
		return new MeshIntersectionState(result, new Vector3(normalAux), this, triangleOwner);
	}
	
	public Triangle getTriOwner(){
		return triOwner; 
	}

	public List<Triangle> getTriangles() {
		return this.triangles;
	}

	private void findMinMaxTransformed(){
		float minX,minY,minZ;
		float maxX,maxY,maxZ;
		minX = Float.MAX_VALUE;
		minY = Float.MAX_VALUE;
		minZ = Float.MAX_VALUE;
		maxX = -Float.MAX_VALUE;
		maxY = -Float.MAX_VALUE;
		maxZ = -Float.MAX_VALUE;
		for (Triangle t : triangles) {
			for (Point3 p : t.points) {
				if(p.x > maxX){
					maxX=p.x;
				}
				if(p.y > maxY){
					maxY=p.y;
				}
				if(p.z > maxZ){
					maxZ=p.z;
				}
				if(p.x < minX){
					minX=p.x;
				}
				if(p.y < minY){
					minY=p.y;
				}
				if(p.z < minZ){
					minZ=p.z;
				}
			}
		}
		
		this.max = new Point3(maxX,maxY,maxZ);
		this.min = new Point3(minX,minY,minZ);
	}


	@Override
	public boolean Intersect(Ray ray, IntersectionState intersection) {

		IntersectionState inter= Intersect(ray.getOrigin(), ray.getDirection());
		
		if(inter==null){
			return false;
		}else{
			intersection.setIntersectionPoint(inter.getIntersectionPoint());
			intersection.setNormal(inter.getNormal());
			intersection.setIntersectionKind(IntersectionKind.OUT);
			intersection.setPrimitive(inter.getPrimitive());
			return true;
		}
		
		
		
	}


	public void transformMesh(Matrix4 transform) {

		transform(transform);
		findMinMaxTransformed();		
		
	} 
	@Override
	public Vector3 getNormal(IntersectionState intersection) {
		return null;
	}


	@Override
	public Point2 getTextureCoords(Point3 point) {
		return null;
	}
	
}
